/*
 * This code is licensed under the Apache License 2.0.
 * Read more at http://blippit.googlecode.com/
 */
package com.googlecode.blippit;

import java.util.Date;

import com.googlecode.blippit.BlipApi.ApiResult;
import com.googlecode.blippit.BlipApi.Song;


import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnCancelListener;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuItem.OnMenuItemClickListener;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TabHost;

public class BlippyActivity extends Activity
implements TabHost.OnTabChangeListener {
	private static final String TAG = "blip";
	private static final int DIALOG_SEARCHING = 9990;
	private static final int DIALOG_LOADING = 9991;
	private boolean canDoAuth;
	private static final String ALL_BLIPS = "ALL_BLIPS";
	private static final String MY_BLIPS = "MY_BLIPS";
	private static final String MY_PLAYLIST = "MY_PLAYLIST";
	private static final String FAVE_BLIPS = "FAVE_BLIPS";

	/** Called when the activity is first created */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		initApi();
		
		setContentView(R.layout.main);

		TabHost th = (TabHost)findViewById(R.id.main_tab_host);
		th.setup();
		LayoutInflater.from(this).inflate(R.layout.tabs, th.getTabContentView(), true);
		Resources r = getResources();
		if (canDoAuth)
			th.addTab(th.newTabSpec(FAVE_BLIPS)
					.setIndicator("Home", r.getDrawable(R.drawable.icon_home_24))
					.setContent(R.id.fave_blips_tab));
		th.addTab(th.newTabSpec("search")
				.setIndicator("Search", r.getDrawable(R.drawable.icon_search_24))
				.setContent(R.id.search_tab));
		if (canDoAuth)
			th.addTab(th.newTabSpec(MY_BLIPS)
					.setIndicator("Mine", r.getDrawable(R.drawable.icon_blip_24))
					.setContent(R.id.my_blips_tab));
		th.addTab(th.newTabSpec(ALL_BLIPS)
				.setIndicator("All", r.getDrawable(R.drawable.icon_all_24))
				.setContent(R.id.all_blips_tab));
		if (canDoAuth)
			th.addTab(th.newTabSpec(MY_PLAYLIST)
					.setIndicator("List", r.getDrawable(R.drawable.icon_playlist_24))
					.setContent(R.id.my_playlist_tab));
		// Hook up the plumbing for the views
		// We want to know when the selected tab changes
		th.setOnTabChangedListener(this);
		// Search can be initiated by enter key in search field
		((EditText)findViewById(R.id.searchText)).setOnKeyListener(new OnKeyListener() {
			public boolean onKey(View v, int keyCode, KeyEvent event) {
				if (keyCode == KeyEvent.KEYCODE_ENTER) {
					initiateSearch();
					return true;  // consume the event
				} else {
					return false;  // we did not consume the event
				}
			}
		});
		// Search can be initiated by search button
		((Button)findViewById(R.id.searchButton)).setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				initiateSearch();
			}
		});
	}

	private void initApi() {
		SharedPreferences prefs = getPreferences(MODE_PRIVATE);
		// Until we add a prefs page, you can create the file
		// /data/data/com.googlecode.blippit/shared_prefs/BlippyActivity.xml
		// with contents like this:
		// <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
		// <map>
		// <string name="apiKey">1234apikey5678</string>
		// <string name="user">user@example.com</string>
		// <string name="password">seekrit</string>
		// <string name="secretKey">your API secret here</string>
		// </map>
		// Or if you're really lazy, you can replace the empty strings below
		// with your account values:
		String ak = prefs.getString("apiKey", "");
		String sk = prefs.getString("secretKey", "");
		String user = prefs.getString("user", "");
		String pass = prefs.getString("password", "");
		if (ak.length() > 0 && sk.length() > 0) {
			BlipApi.init(ak, sk);
		} else {
			new AlertDialog.Builder(this)
			.setTitle("Configuration Error")
			.setMessage("You don't have a Blip API key configured")
			.show();
			return;
		}
		if (user.length() > 0 && pass.length() > 0) {
			BlipApi.auth(user, pass);
			canDoAuth = true;
		} else {
			canDoAuth = false;
		}
		// adjust for difference between the server clock and our clock
		new Thread("API:UtilService.hello") {
			@Override
			public void run() {
				ApiResult r = BlipApi.UtilService.hello();
				if (r == null)
					return;
				long t = new Date().getTime() / 1000;
				int i = r.status_requestTime;
				long offset = i - t - 2;  // Round downward
				Log.i(TAG, "Time offset: " + offset);
				BlipApi.setTimeOffset(offset);
			}
		}.start();
	}

	/** Have our activity manage and persist dialogs, showing and hiding them */
	@Override
	protected Dialog onCreateDialog(int id) {
		ProgressDialog sdialog;
		switch (id) {
		case DIALOG_SEARCHING:
			sdialog = new ProgressDialog(this);
			sdialog.setIndeterminate(true);
			sdialog.setTitle("Searching");
			sdialog.setMessage("Please wait");
			sdialog.setCancelable(true);
			sdialog.setOnCancelListener(new OnCancelListener() {
				public void onCancel(DialogInterface dialog) {
					// TODO: cancel whatever the thread is doing
				}
			});
			return sdialog;
		case DIALOG_LOADING:
			sdialog = new ProgressDialog(this);
			sdialog.setIndeterminate(true);
			sdialog.setTitle("Loading");
			sdialog.setMessage("Please wait");
			sdialog.setCancelable(true);
			sdialog.setOnCancelListener(new OnCancelListener() {
				public void onCancel(DialogInterface dialog) {
					// TODO: cancel whatever the thread is doing
				}
			});
			return sdialog;
		default:
			return null;
		}
	}

	/** Called when the user clicks the "search" button */
	private void initiateSearch() {
		CharSequence query = ((EditText)findViewById(R.id.searchText)).getText();
		if (query.length() > 0) {
			showDialog(DIALOG_SEARCHING);
			AsyncBlipApi.startSearch(query.toString(),
					new AsyncBlipApi.ResultCallback() {
				public void onComplete(final Bundle result) {
					runOnUiThread(new Runnable() {
						public void run() {
							onSearchResult(result);
						}
					});
				}
			});
		}
	}

	public void onSearchResult(Bundle result) {
		dismissDialog(DIALOG_SEARCHING);
		Bundle json = result.getBundle("json");
		onApiResult(R.id.search_results, result, json, BlipApi.toSongArray(json));
	}

	private void reportApiProblem(Bundle result) {
		Bundle json = result.getBundle("json");
		if (json != null) {
			Bundle error = json.getBundle("error");
			if (error != null) {
				// Display the raw error message from the server
				new AlertDialog.Builder(this)
				.setTitle("Blip API Error")
				.setMessage(error.getString("message"))
				.show();
			} else {
				new AlertDialog.Builder(this)
				.setTitle("Blip API Error")
				.setMessage("Not sure what went wrong")
				.show();
			}
		} else {
			String exception = result.getString("exception");
			String message = result.getString("message");
			if (exception != null && message != null) {
				new AlertDialog.Builder(this)
				.setTitle("Error")
				.setMessage(message + "\n\n" + exception)
				.show();
			} else {
				new AlertDialog.Builder(this)
				.setTitle("Error")
				.setMessage("Not sure what went wrong")
				.show();
			}
		}
    }

	private AsyncBlipApi.ResultCallback getApiCallback(final int viewId) {
		return new AsyncBlipApi.ResultCallback() {
			public void onComplete(final Bundle result) {
				runOnUiThread(new Runnable() {
					public void run() {
						onBlipResult(viewId, result);
					}
				});
			}
		};
	}

	private void onBlipResult(int viewId, Bundle result) {
		dismissDialog(DIALOG_LOADING);
		Bundle json = result.getBundle("json");
		onApiResult(viewId, result, json, BlipApi.toBlipArray(json));
	}

	private void onApiResult(int viewId, Bundle result, Bundle json,
			final BlipApi.Song[] songs) {
		ListView results = (ListView) findViewById(viewId);
		if (songs == null) {
			reportApiProblem(result);
			results.setAdapter(new ArrayAdapter<String>(this,
					android.R.layout.simple_list_item_1,
					new String[0]));
		} else if (songs.length == 0) {
			Log.i(TAG, "Empty: " + json.toString());
			results.setAdapter(new ArrayAdapter<String>(this,
					android.R.layout.simple_list_item_1,
					new String[] {"Nothing found"}));
		} else {
			results.setAdapter(new SongListViewAdapter(this,
					R.layout.song_list_item, R.id.song_list_title, songs));
			results.setOnItemClickListener(new AdapterView.OnItemClickListener() {
				public void onItemClick(AdapterView<?> parent, View view,
						int position, long id) {
					Song s = songs[position];
					Log.i(TAG, "Artist: " + s.artist());
					Log.i(TAG, "Title: " + s.title());
					Log.i(TAG, "Type: " + s.type());
					Log.i(TAG, "Location: " + s.url());
					// TODO: do something
				}});
		}
	}

	@Override
	public void onCreateContextMenu(ContextMenu menu, View v,
			ContextMenuInfo menuInfo) {
		Object tag = v.getTag();
		if (tag != null && tag instanceof Song) {
			final Song song = (Song) tag;
			if (song.type().equals("fuzzSong")) {
				menu.add("(on fuzz)");
			} else {
				final Uri uri = Uri.parse(song.url());
				menu.add("Play")
				.setOnMenuItemClickListener(new OnMenuItemClickListener() {
					public boolean onMenuItemClick(MenuItem item) {
						startPlayback(uri, song.artist(), song.title());
						return true;
					}
				});
				menu.add("Download")
				.setOnMenuItemClickListener(new OnMenuItemClickListener() {
					public boolean onMenuItemClick(MenuItem item) {

						return true;
					}
				});
			}
			menu.add("Blip");
		}
	}

	protected void startPlayback(Uri uri, String artist, String title) {
		Intent i = new Intent();
		i.setAction(Intent.ACTION_VIEW);
		i.setData(uri);
		i.putExtra("artist", artist);
		i.putExtra("track", title);
		// TODO: use something that displays the artist and track
		i.setComponent(new ComponentName("com.android.music",
				"com.android.music.StreamStarter"));
		startActivity(i);
	}

	public void onTabChanged(String tabId) {
		if (tabId.equals(ALL_BLIPS)) {
			showDialog(DIALOG_LOADING);
			AsyncBlipApi.startGetPublic(null, null,
					getApiCallback(R.id.all_blips));
		} else if (tabId.equals(FAVE_BLIPS)) {
			showDialog(DIALOG_LOADING);
			AsyncBlipApi.startGetUserHome(null, null,
					getApiCallback(R.id.fave_blips));
		} else if (tabId.equals(MY_BLIPS)) {
			showDialog(DIALOG_LOADING);
			AsyncBlipApi.startGetUserProfile(BlipApi.getUsername(),
					null, null, getApiCallback(R.id.my_blips));
		} else if (tabId.equals(MY_PLAYLIST)) {
			showDialog(DIALOG_LOADING);
			AsyncBlipApi.startGetUserPlayList(BlipApi.getUsername(),
					getApiCallback(R.id.my_playlist));
		}
	}
}
